# Alert Dialog

<Subtitle>A dialog that requires a user response to proceed.</Subtitle>
<Meta
  name="description"
  content="A high-quality, unstyled React alert dialog component that requires a user response to proceed."
/>

import { DemoAlertDialogHero } from './demos/hero';

<DemoAlertDialogHero />

## Anatomy

Import the component and assemble its parts:

```jsx title="Anatomy"
import { AlertDialog } from '@base-ui-components/react/alert-dialog';

<AlertDialog.Root>
  <AlertDialog.Trigger />
  <AlertDialog.Portal>
    <AlertDialog.Backdrop />
    <AlertDialog.Viewport>
      <AlertDialog.Popup>
        <AlertDialog.Title />
        <AlertDialog.Description />
        <AlertDialog.Close />
      </AlertDialog.Popup>
    </AlertDialog.Viewport>
  </AlertDialog.Portal>
</AlertDialog.Root>;
```

## Examples

### Open from a menu

In order to open a dialog using a menu, control the dialog state and open it imperatively using the `onClick` handler on the menu item.

```tsx {12-13,17-18,24-25,28-29} title="Connecting a dialog to a menu"
import * as React from 'react';
import { AlertDialog } from '@base-ui-components/react/alert-dialog';
import { Menu } from '@base-ui-components/react/menu';

function ExampleMenu() {
  const [dialogOpen, setDialogOpen] = React.useState(false);

  return (
    <React.Fragment>
      <Menu.Root>
        <Menu.Trigger>Open menu</Menu.Trigger>
        <Menu.Portal>
          <Menu.Positioner>
            <Menu.Popup>
              {/* Open the dialog when the menu item is clicked */}
              <Menu.Item onClick={() => setDialogOpen(true)}>Open dialog</Menu.Item>
            </Menu.Popup>
          </Menu.Positioner>
        </Menu.Portal>
      </Menu.Root>

      {/* Control the dialog state */}
      <AlertDialog.Root open={dialogOpen} onOpenChange={setDialogOpen}>
        <AlertDialog.Portal>
          <AlertDialog.Backdrop />
          <AlertDialog.Popup>
            {/* prettier-ignore */}
            {/* Rest of the dialog */}
          </AlertDialog.Popup>
        </AlertDialog.Portal>
      </AlertDialog.Root>
    </React.Fragment>
  );
}
```

### Close confirmation

This example shows a nested confirmation dialog that opens if the text entered in the parent dialog is going to be discarded.

To implement this, both dialogs should be controlled. The confirmation dialog may be opened when `onOpenChange` callback of the parent dialog receives a request to close. This way, the confirmation is automatically shown when the user clicks the backdrop, presses the Esc key, or clicks a close button.

Use the `[data-nested-dialog-open]` selector and the `var(--nested-dialogs)` CSS variable to customize the styling of the parent dialog. Backdrops of the child dialogs won't be rendered so that you can present the parent dialog in a clean way behind the one on top of it.

import { DemoDialogCloseConfirmation } from '../dialog/demos/close-confirmation';

<DemoDialogCloseConfirmation compact />

### Detached triggers

An alert dialog can be controlled by a trigger located either inside or outside the `<AlertDialog.Root>` component.
For simple, one-off interactions, place the `<AlertDialog.Trigger>` inside `<AlertDialog.Root>`, as shown in the example at the top of this page.

However, if defining the alert dialog's content next to its trigger is not practical, you can use a detached trigger.
This involves placing the `<AlertDialog.Trigger>` outside of `<AlertDialog.Root>` and linking them with a `handle` created by the `AlertDialog.createHandle()` function.

```jsx title="Detached triggers" {3,5} "handle={demoDialog}"
const demoAlertDialog = AlertDialog.createHandle();

<AlertDialog.Trigger handle={demoAlertDialog}>Open</AlertDialog.Trigger>

<AlertDialog.Root handle={demoAlertDialog}>
  ...
</AlertDialog.Root>
```

import { DemoAlertDialogDetachedTriggersSimple } from './demos/detached-triggers-simple';

<DemoAlertDialogDetachedTriggersSimple />

### Multiple triggers

A single alert dialog can be opened by multiple trigger elements.
You can achieve this by using the same `handle` for several detached triggers, or by placing multiple `<AlertDialog.Trigger>` components inside a single `<AlertDialog.Root>`.

```jsx title="Multiple triggers within the Root part"
<AlertDialog.Root>
  <AlertDialog.Trigger>Trigger 1</AlertDialog.Trigger>
  <AlertDialog.Trigger>Trigger 2</AlertDialog.Trigger>
  ...
</AlertDialog.Root>
```

```jsx title="Multiple detached triggers"
const demoAlertDialog = AlertDialog.createHandle();

<AlertDialog.Trigger handle={demoAlertDialog}>Trigger 1</AlertDialog.Trigger>
<AlertDialog.Trigger handle={demoAlertDialog}>Trigger 2</AlertDialog.Trigger>
<AlertDialog.Root handle={demoAlertDialog}>
  ...
</AlertDialog.Root>
```

The alert dialog can render different content depending on which trigger opened it.
This is achieved by passing a `payload` to the `<AlertDialog.Trigger>` and using the function-as-a-child pattern in `<AlertDialog.Root>`.

The payload can be strongly typed by providing a type argument to the `createHandle()` function:

```jsx title="Detached triggers with payload" {1,3,7,12}
const demoAlertDialog = AlertDialog.createHandle<{ message: string }>();

<AlertDialog.Trigger handle={demoAlertDialog} payload={{ message: 'Trigger 1' }}>
  Trigger 1
</AlertDialog.Trigger>

<AlertDialog.Trigger handle={demoAlertDialog} payload={{ message: 'Trigger 2' }}>
  Trigger 2
</AlertDialog.Trigger>

<AlertDialog.Root handle={demoAlertDialog}>
  {({ payload }) => (
    <AlertDialog.Portal>
      <AlertDialog.Popup>
        <AlertDialog.Title>Alert dialog</AlertDialog.Title>
        {payload !== undefined && (
          <AlertDialog.Description>
            Confirming {payload.message}
          </AlertDialog.Description>
        )}
      </AlertDialog.Popup>
    </AlertDialog.Portal>
  )}
</AlertDialog.Root>
```

### Controlled mode with multiple triggers

You can control the alert dialog's open state externally using the `open` and `onOpenChange` props on `<AlertDialog.Root>`.
This allows you to manage the alert dialog's visibility based on your application's state.
When using multiple triggers, you have to manage which trigger is active with the `triggerId` prop on `<AlertDialog.Root>` and the `id` prop on each `<AlertDialog.Trigger>`.

Note that there is no separate `onTriggerIdChange` prop.
Instead, the `onOpenChange` callback receives an additional argument, `eventDetails`, which contains the trigger element that initiated the state change.

import { DemoAlertDialogDetachedTriggersControlled } from './demos/detached-triggers-controlled';

<DemoAlertDialogDetachedTriggersControlled />

## API reference

<Reference
  component="AlertDialog"
  parts="Root, Trigger, Portal, Backdrop, Viewport, Popup, Title, Description, Close"
/>
